﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Criterion;
using SaleLibrary.Score;
using SaleLibrary.Sale;
using System.Data;
using SaleLibrary.Tools;
using System.ComponentModel;
using BrokerBase.Lib.Client;
using BrokerBase.Lib.Tool;

namespace SaleLibrary.License
{
    
    //第3位表示有效期的低位
    //第23位表示有效期的高位

    public class ActiveCode : INotifyPropertyChanged
    {
        
        public const int DEFAULT_INVITED_CODE_QTY = 10;

        private static readonly char[] Seeds = new char[31] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', '2', '3', '4', '5', '6', '7', '8', '9' };
        private const int SERIAL_MAX_LENGTH = 25;

        private int period;
        private double amount;

        public virtual event PropertyChangedEventHandler PropertyChanged;


        public virtual void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }


        }

        public static bool IsExistCode(string code, ISession sess)
        {
            ActiveCode ac = sess.CreateQuery("from ActiveCode where Code='" + code + "'").UniqueResult<ActiveCode>();

            return ac == null ? false : true;
        }
        /// <summary>
        /// 保存一个新建的序列号对象
        /// </summary>
        /// <param name="activeCode"></param>
        /// <param name="sf"></param>
        public static void SaveNewActiveCode(ActiveCode activeCode,ISessionFactory sf)
        {
            ISession sess = null;
            ITransaction tx = null;

            sess = sf.GetCurrentSession();
            tx = sess.BeginTransaction();

            try
            {
                if (activeCode.Id == 0) //id==0表示还没有保存过
                {
                    activeCode.Code = CreateCode();
                    int existCount = 0;
                    while (true)//考虑存在重复的的情况，所以首先查找是否存在重复的code,如果存在则新建一个code再保存
                    {
                        existCount = sess.CreateSQLQuery("select count(*) from sale_activecode where code='" + activeCode.Code + "'").List<int>()[0];
                        if (existCount == 0)
                        {
                            sess.Save(activeCode);
                            tx.Commit();
                            break;
                        }
                        else
                        {
                            activeCode.Code = CreateCode();
                        }
                    }
                }
                else
                {
                    sess.SaveOrUpdate(activeCode);
                }

            }
            catch (Exception er)
            {
                if (tx.IsActive)
                    tx.Rollback();
                throw er;
            }
        }
        /// <summary>
        /// 创建一个序列号对象
        /// </summary>
        /// <param name="edition"></param>
        /// <param name="period"></param>
        /// <param name="regPeriod"></param>
        /// <returns></returns>
        public static ActiveCode CreateActiveCode(EditionType edition,int period,int regPeriod)
        {
            ActiveCode ac = new ActiveCode();

            ac.Edition = edition;
            ac.Code = CreateCode();
            ac.IsRenewal = false;
            ac.CreateTime = DateTimeUtil.ChinaStandardTime;
            ac.Edition = edition;
            ac.Period = period;
            ac.RegPeriod = regPeriod;
            ac.Sends = new List<ActiveCodeSend>();
            ac.Regs = new List<ActiveCodeReg>();
            ac.IsUsed = true;
            return ac;
        }
        /// <summary>
        /// 创建一个序列号文本
        /// </summary>
        /// <returns></returns>
        public static string CreateCode()
        {
            Random r = new Random(GetRandomSeed());

            string s = null;

            for (int i = 0; i < SERIAL_MAX_LENGTH; i++)
            {
                int index = r.Next(1, Seeds.Count());
                s += Seeds[index];

                int i2 = i + 1;

                if (i2 % 5 == 0 && i2 != SERIAL_MAX_LENGTH)
                    s += "-";
            }

            return s;
        }

        private static  int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }

        /// <summary>
        /// 验证客户端提交的注册信息是否有效
        /// </summary>
        /// <param name="presenterName"></param>
        /// <param name="userName"></param>
        /// <param name="licenseCode"></param>
        /// <param name="activeCode"></param>
        /// <param name="serialNo"></param>
        /// <param name="sess"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static ActiveCode Verify(RegistrantInfo registrantInfo, string activeCode, TerminalInfo terminalInfo ,ISession sess, out string message)
        {

            ActiveCode ac = null;
            ActiveCodeReg reg=null;

            if (string.IsNullOrEmpty(activeCode))
            {
                message = "激活码不能为空";
                return null;
            }

            if (terminalInfo == null )
            {
                message = "客户端信息错误";
                return null;
            }

            if (string.IsNullOrEmpty(registrantInfo.UserName))
            {
                message = "注册名不能为空";
                return null;
            }

            if (registrantInfo.PresenterName == registrantInfo.UserName)
            {
                message = "推荐不能是自己";
                return null;
            }

            if (!string.IsNullOrEmpty(registrantInfo.PresenterName) && !Client.ExistOfName(registrantInfo.PresenterName, sess))
            {
                
                message = "推荐人不存在";
                return null;
            }

            IList<ActiveCode> acs = sess.CreateCriteria<ActiveCode>().Add(Restrictions.Eq("Code", activeCode)).Add(Restrictions.IsNotNull("SendTime")).Add(Restrictions.Eq("IsUsed", true)).List<ActiveCode>();

            if (acs.Count == 0)
            {
                message = "序列号不存在";
                return null;
            }
            else
            {
                ac = acs[0];
            }

            IClient client = Client.LoadByName(registrantInfo.UserName, sess);

            if (client == null)//假如用户不存在
            {
                if (ac.IsRenewal)
                {
                    message = "要续费的注册名不存在";
                    return null;
                }

                if (ac.RegTime != null )//新用户不可能使用已存在的激活码!
                {
                    message = "激活码已经被使用过";
                    return null;
                }
            }
            else//假如用户存在
            {
                if (ac.RegTime==null)//激活码还没有注册过
                {
                    //假如不是试用用户，并且激活码不是续费
                    if (!client.IsTrial && !ac.IsRenewal)
                    {
                        message = "已存在的注册用户只能使用续费类型的激活码" + Environment.NewLine + "如果是新建用户请检查用户名是否存在";
                        return null;
                    }

                    if (client.IsTrial && ac.IsRenewal)
                    {
                        message = "试用注册用户不能使用续费类型的激活码";
                        return null;
                    }
                }
                else//用户名存在并且已经激活，首先判断用户名是否匹配，再判断机器硬件是否匹配
                {
                    if (ac.Registrant.Id != client.Id)
                    {
                        message = "用户名与激活码不匹配";
                        return null;
                    }
                    else
                    {
                        int maxId=ac.Regs.Max(p=>p.Id);
                        ActiveCodeReg r = ac.Regs.FirstOrDefault(p => p.Id == maxId);

                        if (r.DISKSerialNo != terminalInfo.DISKSerialNo && r.MACSerialNo != terminalInfo.MACSerialNo && r.MBSerialNo != terminalInfo.MBSerialNo)
                        {
                            message = "激活码已经被使用过";
                            return null;
                        }
                    }
                }

            }

            //激活码第一次注册，并且注册时间是否已经超出有效注册期
            if (ac.RegTime == null && DateTimeUtil.ChinaStandardTime > ac.SendTime.Value.AddDays(ac.RegPeriod))
            {
                message = "激活码注册时间已经过期!";
                return null;
            }

            //Client user = ac.Client;

            if (ac.Registrant != null && ac.Registrant.Name != registrantInfo.UserName)//续费的用户名必须匹配!
            {
                message = "激活码与注册名不匹配";
                return null;
            }


            
            if (ac.Edition == EditionType.Evaluation)
            {
                //假如是试用码，不允许在多台机器上注册！
                if (ac.RegTime != null)
                {
                    if (ac.Regs.Count > 0)
                    {
                        reg = ac.Regs[0];

                        if (reg.DISKSerialNo != terminalInfo.DISKSerialNo && reg.MACSerialNo != terminalInfo.MACSerialNo)
                        {
                            message = "该注册码已经注册过!";
                            return null;
                        }
                    }
                }
                //同一台机器不允许多次使用试用码
                IList<ActiveCodeReg> regs = ActiveCodeReg.LoadByTerminalInfoWithAllMatch(terminalInfo, sess);

                if (regs.Count > 0)
                {
                    message = "该客户端已经使用过试用注册码，不能多次使用!";
                    return null;
                }
            }


            message = null;
            return ac;
        }
        /// <summary>
        /// 注册客户端
        /// </summary>
        /// <param name="presenterName"></param>
        /// <param name="userName"></param>
        /// <param name="licenseCode"></param>
        /// <param name="activeCode"></param>
        /// <param name="serials"></param>
        /// <param name="isRenewal"></param>
        /// <param name="sf"></param>
        /// <param name="Message"></param>
        /// <returns></returns>
        public static ActiveCodeReg Register(ActiveCode activeCode,RegistrantInfo registrantInfo, TerminalInfo terminalInfo,string ipAddress, ISession sess, out string Message)
        {
            ActiveCodeReg reg = activeCode.CreateReg();

            IClient client=null;
            IClient parent=null;
            bool isNewUser=false;

            //判断是否需要新增加用户
            if (!Client.ExistOfName(registrantInfo.UserName, sess))
            {
                client = new Client();
                parent = null;

                client.Name = registrantInfo.UserName;
                client.LicenseCode = Guid.NewGuid().ToString();//产品序列号
                client.EMail = registrantInfo.EMail;
                client.CreateDate = DateTimeUtil.ChinaStandardTime;
                client.Leaf = true;//新建的为最末级节点
                client.InviteCodeQty = ActiveCode.DEFAULT_INVITED_CODE_QTY;//默认邀请码等于5个

                //如果推荐人不为空，则指定父节点
                if (!string.IsNullOrEmpty(registrantInfo.PresenterName))
                {
                    parent = Client.LoadByName(registrantInfo.PresenterName, sess);
                    client.Parent = parent;
                    parent.Leaf = false;
                    sess.SaveOrUpdate(parent);//是否最末层已经更新，所以需要保存父节点
                }

                client.Level = client.Parent == null ? 1 : client.Parent.Level + 1;//层级等于父级节点层级加1

                client.RegTime = client.CreateDate;
                

                isNewUser = true;
            }
            else
            {
                client = Client.LoadByName(registrantInfo.UserName, sess);
            }

            client.Policy = activeCode.Policy;//更新客户积分政策等于当前注册激活码的积分政策
            client.LastRegTime = DateTimeUtil.ChinaStandardTime;          //设置最后一次激活的时间
            
            if (activeCode.RegTime==null)//还没有注册过
            {
                DateTime current = DateTimeUtil.ChinaStandardTime;

                activeCode.Registrant = client;//如果还没有被注册过，就把客户关联到激活码

                if (isNewUser)//假如是新建用户
                {
                    activeCode.BeginTime = new DateTime(current.Year, current.Month, current.Day);//只取年-月-日
                }
                else//产品升级或续费
                {
                    DateTime? maxEndTime = client.ActiveCodes.Max(p => p.EndTime);//找到该用户激活码最大的有效期结束时间

                    if (current > maxEndTime)//假如当前时间已经大于用户最大的有效期结束时间(表明客户中间有个间断期)
                    {
                        activeCode.BeginTime = new DateTime(current.Year, current.Month, current.Day);//只取年-月-日
                    }
                    else
                    {
                        activeCode.BeginTime = maxEndTime.Value.AddDays(1);//最大日期加一条
                    }
                }

                activeCode.EndTime = activeCode.BeginTime.Value.AddMonths(activeCode.Period);
                activeCode.LicenseCode = client.LicenseCode;//如果是第一次激活，激活码序列号等于客户对应的产品序列号
                
                client.TotalAmount += activeCode.Amount;    //更新累计金额
            }

            sess.SaveOrUpdate(client);

            client.FullPath = client.Parent == null ? client.Id.ToString() : client.Parent.FullPath + "." + client.Id;
            sess.SaveOrUpdate(client);//更新fullpath;

            reg.DISKSerialNo = terminalInfo.DISKSerialNo;
            reg.MACSerialNo = terminalInfo.MACSerialNo;
            reg.OSVersion = terminalInfo.OSVersion;
            reg.RegIPAddress = ipAddress;
            reg.MBSerialNo = terminalInfo.MBSerialNo;

            activeCode.Regs.Add(reg);

            //更新所有(最大32层)推荐人的积分记录,只有不是续费类型，并且第一次激活时才更新积分，重复激活不更新积分！
            if (!activeCode.IsRenewal && activeCode.RegTime == null )
            {
                UpdateScore(reg, sess);
            }

            activeCode.RegTime = DateTimeUtil.ChinaStandardTime;//激活码最后注册时间
            sess.SaveOrUpdate(activeCode);//保存修改后的激活码和激活记录

            Message = null;
            return reg;

        }
        /// <summary>
        /// 更新所有(符合规则)父节点的积分
        /// </summary>
        /// <param name="reg"></param>
        /// <param name="sess"></param>
        public static void UpdateScore(ActiveCodeReg reg,ISession sess)
        {
            int i = 0;
            IClient client = reg.ActiveCode.Registrant.Parent;

            IScoreRecordType socRecType=sess.CreateCriteria<ScoreRecordType>().Add(Restrictions.Eq("TypeStyle",1)).List<ScoreRecordType>()[0];
            
            //使用NHibernate来更新数据，如果效率不高，以后可以采用存储过程直接写sql来实现
            while (client != null && i<= SaleLibrary.Score.ScoreRule.INTERNAL_MAX_LEVEL )
            {
                i++;

                if (!client.IsTrial && client.Policy != null)
                {
                    IScoreRule rule = client.Policy.Rules.FirstOrDefault(p => p.Edition == reg.ActiveCode.Edition);

                    //规则不为空，并且当期层级小于规则的最大限制，并且金额大于规则的最小限制
                    if ((rule != null && i <= rule.MaxLevel) || rule == null)
                    {
                        IScoreRecord scoreRecord = client.CreateOrUpdateScoreRecord(socRecType, reg, rule, i, null, sess);

                        //client.TotalScore += scoreRecord.Score; //更新父节点的累计积分
                        client.UpdateScore(scoreRecord.Score, sess);

                        sess.SaveOrUpdate(scoreRecord);         //保存积分记录
                        sess.SaveOrUpdate(client);
                    }
                }
                client = client.Parent;//获取父节点
            }
        }
        /// <summary>
        /// 创建一个注册记录
        /// </summary>
        /// <returns></returns>
        public virtual ActiveCodeReg CreateReg()
        {
            ActiveCodeReg reg = new ActiveCodeReg();
            reg.ActiveCode = this;
            reg.RegTime = DateTimeUtil.ChinaStandardTime;
            return reg;
        }

        /// <summary>
        /// 创建一个发送记录
        /// </summary>
        /// <returns></returns>
        public virtual ActiveCodeSend CreateSend()
        {
            ActiveCodeSend send = new ActiveCodeSend();
            send.MailSubject = "激活码";
            send.MailBody = ActiveCodeSend.GetMailBody(this);
            send.ActiveCode = this;
            return send;
        }
        /// <summary>
        /// id
        /// </summary>
        public virtual int Id { get; set; }
        /// <summary>
        /// 25位序列号
        /// </summary>
        public virtual string Code { get; set; }
        /// <summary>
        /// 激活码类别(版本)
        /// </summary>
        public virtual EditionType Edition { get; set; }
        /// <summary>
        /// 是否续费
        /// </summary>
        public virtual bool IsRenewal { get; set; }
        /// <summary>
        /// 有效期（月）
        /// </summary>
        public virtual int Period 
        {
            get { return period; }
            set
            {
                period = value;
                NotifyPropertyChanged("Period");
            }
        }
        /// <summary>
        /// 创建时间
        /// </summary>
        public virtual DateTime CreateTime { get; set; }
        /// <summary>
        /// 是否有效
        /// </summary>
        public virtual bool IsUsed { get; set; }
        /// <summary>
        /// 发送时间
        /// </summary>
        public virtual DateTime? SendTime { get; set; }
        /// <summary>
        /// 注册期间
        /// </summary>
        public virtual int RegPeriod { get; set; }
        /// <summary>
        /// 注册时间
        /// </summary>
        public virtual DateTime? RegTime { get; set; }
        /// <summary>
        /// 发送记录列表
        /// </summary>
        public virtual IList<ActiveCodeSend> Sends { get; set; }
        /// <summary>
        /// 注册记录列表
        /// </summary>
        public virtual IList<ActiveCodeReg> Regs { get; set; }
        /// <summary>
        /// 开始日期
        /// </summary>
        public virtual DateTime? BeginTime { get; set; }
        /// <summary>
        /// 结束日期
        /// </summary>
        public virtual DateTime? EndTime { get; set; }


        public virtual IScorePolicy Policy { get; set; }
        /// <summary>
        /// 积分策略
        /// </summary>
        //public virtual IScoreRule DefaultScoreRule 
        //{
        //    get { return defaultScoreRule; }
        //    set
        //    {
        //        defaultScoreRule = value;
        //        NotifyPropertyChanged("DefaultScoreRule");
        //    }
        //}
        /// <summary>
        /// 金额
        /// </summary>
        public virtual double Amount
        {
            get { return amount; }
            set
            {
                amount = value;
                NotifyPropertyChanged("Amount");
            }
        }
        /// <summary>
        /// 产品序列号(计算数字指纹，其它暂时没什么用)
        /// </summary>
        public virtual string LicenseCode { get; set; }
        /// <summary>
        /// 注册用户
        /// </summary>
        public virtual IClient Registrant { get; set; }
        /// <summary>
        /// 推荐人
        /// </summary>
        public virtual IClient Presenter { get; set; }


        public virtual bool IsSend { get { return SendTime == null ? false : true; } }
    }
}
